package com.syni.mdd.yhd.common.all.utils.auth;

import com.syni.mdd.sjb.common.component.utils.common.utils.MatchEncryptionUtils;
import com.syni.mdd.yhd.common.all.constants.Constants;
import com.syni.mdd.sjb.common.component.utils.common.utils.RequestHeaderData;
import com.syni.mdd.sjb.common.component.utils.redis.utils.RedisTemplateUtils;;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @className 对称加密
 * @description TOO
 * @Author cfx
 * @DATE 2020/4/10 14:41
 * @VERSION 1.0
 **/
@Log4j2
//@Component
public class SymmetricEncryptionAuth implements TokenAuth{
    private static Map<String,String> MAP_TOKENS = new HashMap<>();
    // 编码密码,可自定义

    private static final String ENCODED_PASSWORD = "dianxiangshenghuoapp";
    @Value("${app.token.expire}")
    private int VALID_TIME; // token有效期(秒)
    public static final int TOKEN_ERROR = -1; // 非法
    public static final int TOKEN_OVERDUE = 0; // 无效
    public static final int TOKEN_SUCCESS = 1; // 验证成功


    /**
     * 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下
     * 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储
     * @param str: 该字符串可自定义,在校验token时要保持一致
     * @return
     */
    public String getToken(String userId,String roleId) {
        RequestHeaderData requestHeaderData = new RequestHeaderData();
        String devId = requestHeaderData.getString("devid");
        int client = requestHeaderData.getClient();
        //System.out.println("dev length : " + devId.length());
        //String token = encoded(random + ":" + userId + ":" + roleId);
        long nowTime = System.currentTimeMillis();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(devId + ":");
        stringBuilder.append(userId + ":");
        stringBuilder.append(roleId + ":");
        stringBuilder.append(client + ":");
        stringBuilder.append(nowTime);
        String token = MatchEncryptionUtils.encoded(stringBuilder.toString());
        //System.out.println("token length : " + token.length());
        //MAP_TOKENS.put(str, token);
        //放入redis中
        String userTokenKey = Constants.REDIS_KEY_TOKEN + userId + ":" + roleId + ":" + client;
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(userTokenKey,token,VALID_TIME, TimeUnit.DAYS);
        return token;

        /*String devId = requestHeaderData.getString("devid");
        List<String> tokens = new ArrayList<>();
        if(StringUtils.isNotBlank(devId)){
            tokens.add(devId);
        }
        tokens.add(userId);
        tokens.add(roleId);
        String token = encoded(StringUtils.join(tokens,":"));
        //放入redis中
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(Constants.REDIS_KEY_TOKEN + userId + ":" + roleId,token,VALID_TIME, TimeUnit.DAYS);*/
        //return token;
    }

    @Override
    public String getToken(String userId, String roleId, Integer client) {
        return null;
    }

    /**
     * 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下
     * 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储
     * @param str: 该字符串可自定义,在校验token时要保持一致
     * @return
     */
    public String getToken(String userId,String roleId,boolean isCanMoreUse) {
        RequestHeaderData requestHeaderData = new RequestHeaderData();
        int client = requestHeaderData.getClient();
        String userTokenKey = Constants.REDIS_KEY_TOKEN + userId + ":" + roleId + ":" + client;
        if(isCanMoreUse){
            if(RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                return RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            }
        }
        //getToken(userId,roleId);
        String devId = requestHeaderData.getString("devid");
        long nowTime = System.currentTimeMillis();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(devId + ":");
        stringBuilder.append(userId + ":");
        stringBuilder.append(roleId + ":");
        stringBuilder.append(client + ":");
        stringBuilder.append(nowTime);
        String token = MatchEncryptionUtils.encoded(stringBuilder.toString());
        //放入redis中
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(userTokenKey,token,VALID_TIME, TimeUnit.DAYS);
        return token;
    }

    @Override
    public String getToken(String userId, String roleId, Integer client, boolean isNotRefresh) {
        return null;
    }

    /**
     * 校验token的有效性
     * @param token
     * @return
     */
    public int checkToken(String token,String userId) {
        if (token == null) {
            return TOKEN_ERROR;
        }
        try{
            String[] tArr = MatchEncryptionUtils.decoded(token).split(":");
            if(tArr.length != 3) {
                if (tArr.length != 5) {
                    return TOKEN_ERROR;
                }
            }
            //检查token是否无效
            String roleId = tArr[2];
            String client = "";
            if(tArr.length > 3) {
                client = tArr[3];
            }
            String userTokenKey = Constants.REDIS_KEY_TOKEN + userId + ":" + roleId;
            if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                userTokenKey = Constants.REDIS_KEY_TOKEN + userId + ":" + roleId + ":" + client;
                if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)) {
                    return TOKEN_OVERDUE;
                }
            }
            String checkToken = RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            if(!checkToken.equals(token)){
                userTokenKey = Constants.REDIS_KEY_TOKEN + userId + ":" + roleId + ":" + client;
                if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)) {
                    return TOKEN_OVERDUE;
                }
                checkToken = RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
                if (!checkToken.equals(token)) {
                    return TOKEN_OVERDUE;
                }
            }
            return TOKEN_SUCCESS;
        }catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return TOKEN_ERROR;
    }

    @Override
    public int checkToken(String token) {
        return 0;
    }

    /**获取当前时间戳（10位整数）*/
    public static int getCurrentTime() {
        return (int)(System.currentTimeMillis()/1000);
    }

    /**
     * 移除过期的token
     */
    public void removeInvalidToken() {
        int currentTime = getCurrentTime();
        for (Map.Entry<String,String> entry : MAP_TOKENS.entrySet()) {
            String[] tArr = MatchEncryptionUtils.decoded(entry.getValue()).split(",");
            int tokenTime = Integer.parseInt(tArr[0]);
            if(currentTime-tokenTime > VALID_TIME){
                MAP_TOKENS.remove(entry.getKey());
            }
        }
    }

}
